package dk.ahp.getmeoff;

import android.app.Service;
import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

public class PositionService extends Service {
	private static final String TAG = "PositionService";
	private int updateDelay=15000;
	private DoStuff doStuff;
	private Boolean running = false;
	private LocationHandling locate = null;
	
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		doStuff = new DoStuff();
		GetMeOffApplication.getMeOffApplication.updateThread = doStuff;
		locate = new LocationHandling();
		locate.start();
		Log.d(TAG, "onCreate");
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		super.onStartCommand(intent, flags, startId);
		if(!running) {
			doStuff.start();
		}
		Log.d(TAG, "onStartCommand");
		return START_STICKY;
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		this.doStuff.interrupt();
		running = false;
		this.doStuff = null;
		locate.stop();
		Log.d(TAG, "onDestroy");
	}
	
	/**
	 * Thread that check position when needed.
	 */
	private class DoStuff extends Thread {
		private final String LTAG = TAG + " " + DoStuff.class.getSimpleName();
		private float fakeDist= -1;
		public DoStuff() {
			super("DoStuff");
		}
		
		@Override
		public void run() {
			running = true;
			while(running) {
				try {
					Location tmpLoc = locate.get();
					if(null != tmpLoc) {
						GetMeOffApplication.getMeOffApplication.currentLocation = tmpLoc;
						Log.d(LTAG, "Current location updated: " + GetMeOffApplication.getMeOffApplication.currentLocation);
					}
					long sysTime = System.currentTimeMillis();
					// hvis en destination har aktiv alarm så skal vi have en loc nu (og ikke en gammel).
					if(null != GetMeOffApplication.getMeOffApplication.activeDestination) {
						if (null == tmpLoc || (sysTime - tmpLoc.getTime() > 10000)) {
							locate.setUpdateFreq(1000);
							tmpLoc = locate.get();
							if (null != tmpLoc) {
								GetMeOffApplication.getMeOffApplication.currentLocation = tmpLoc;
								locate.setUpdateFreq(5000);
							}
						} else {
							// beregn afstand til destiantion
							Location dest = GetMeOffApplication.getMeOffApplication.activeDestination.getDestination();
							float afstand = tmpLoc.distanceTo(dest);  
							GetMeOffApplication.getMeOffApplication.distanceToDest = afstand;
							if (0 > fakeDist) {
								fakeDist = afstand;
							}
							String alarmDistStr = GetMeOffApplication.getMeOffApplication.prefs.getString("StandardDist", "500");
							float alarmDist = Float.parseFloat(alarmDistStr);
							if (afstand < alarmDist) {
								// Så er det nu vi skal af bussen.
								Log.d(LTAG, "NU ER VI TÆT PÅ, starter alarm");
								GetMeOffApplication.getMeOffApplication.activeDestination = null; // så får vi ikke alarm hele tiden efter vi er nået frem.
								PositionService.this.sendBroadcast(new Intent("dk.ahp.getmeoff.ALARM"));
							}
							PositionService.this.sendBroadcast(new Intent("dk.ahp.getmeoff.STATUS"));
						}
					} else { 
						locate.setUpdateFreq(60000);
					}
					if (null != GetMeOffApplication.getMeOffApplication.activeDestination &&
							GetMeOffApplication.getMeOffApplication.prefs.getBoolean("fakeMovement", false)) {
						GetMeOffApplication.getMeOffApplication.distanceToDest = fakeDist;
						PositionService.this.sendBroadcast(new Intent("dk.ahp.getmeoff.STATUS"));
						if(fakeDist < 500 && fakeDist >0) {
							GetMeOffApplication.getMeOffApplication.activeDestination = null; // så får vi ikke alarm hele tiden efter vi er nået frem.
							PositionService.this.sendBroadcast(new Intent("dk.ahp.getmeoff.ALARM"));
						}
						fakeDist -= 20;
						updateDelay = 1000;// der skal ske noget.
					}
					Thread.sleep(updateDelay);
				} catch (InterruptedException e) {
					Log.d(LTAG, "InterruptedException: " + e);
					fakeDist = -1;
				}
			}
		}
	}
	
	private class LocationHandling implements LocationListener {
		private final String LTAG = TAG + " " + LocationHandling.class.getSimpleName();
		private LocationManager locationManager;
		private Location loc = null;
		private Boolean locUpdated = false;
		private long updateFreq = 60000;
		
		public LocationHandling() {
			locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
		}
		
		public void start() {
			Location latestKnownLocation = null;
			for (String provider : locationManager.getAllProviders()) {
				loc = locationManager.getLastKnownLocation(provider);
				if (null == loc) {
					continue;
				}
				if ("gps".equals(loc) && false == locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
				{
					continue;
				}
				if (null == latestKnownLocation) {
					latestKnownLocation = loc;
				} else if (loc.getTime() > latestKnownLocation.getTime()) {
					latestKnownLocation = loc;
				}
			}
			
			long now = System.currentTimeMillis();
			if ((null == latestKnownLocation) || (now - latestKnownLocation.getTime() > 1000*3600*2 )) {
				loc = null; 
			}
			
			if (null != latestKnownLocation) {
				Log.d(LTAG, "Fandt loc: " + latestKnownLocation);
				GetMeOffApplication.getMeOffApplication.bestGuessLocation = latestKnownLocation;
			}
	
			for (String provider : locationManager.getAllProviders()) {
				locationManager.requestLocationUpdates(provider, updateFreq, 100, this);
			}
		}
		
		public void setUpdateFreq(long sampleTid) {
			if (sampleTid != updateFreq) {
				updateFreq = sampleTid;
				for (String provider : locationManager.getAllProviders()) {
					locationManager.requestLocationUpdates(provider, sampleTid, 100, this);
				}
			}
		}
		
		public Location get() {
			if(true == locUpdated) { 
				locUpdated = false;
				return loc;
			}
			return null;
		}
		
		public void stop() {
			locationManager.removeUpdates(this);
			Log.d(LTAG, "stop");
		}
		
		@Override
		public void onLocationChanged(Location l) {
			loc = l;
			locUpdated = true;
			doStuff.interrupt();
			Log.d(LTAG, "Location updated: " + l.toString());
		}

		@Override
		public void onProviderDisabled(String arg0) {
			// TODO Auto-generated method stub
		}

		@Override
		public void onProviderEnabled(String arg0) {
			// TODO Auto-generated method stub
		}

		@Override
		public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
			// TODO Auto-generated method stub
		}
	}
}
